<!---
*****************************************************************************************************
*Author: Jon Wallen                                                                                 *
*www.cfshopkart.com                                                                                 *
*                                                                                                   *
*                                                                                                   *
*Performs a variety of form validation functions.                                                   *
*                                                                                                   *
*Version:  1.0                                                                                      *
*****************************************************************************************************

Revision History:

None.

To use:

In your form add hidden form fields:

accepted field name:

validation_required {checks for empty fields)
validation_email (checks emails are formatted correctly)
validation_password {checks two password fields to make sure they match)
validation_captcha {checks a string an encrypted string and makes sure they match.  Used with CFIMAGE action="captcha"

Field Values:

For each hidden field create a semi-colon delmited list and then seperate the values for each field with a pipe (|).

validate_required: {form field name}|{Error Message if validation fails};...
validate_email: {form field name}|{Error Message if validation fails};...
validate_password: {Password Field Name}|{Confirmation Password Field Name}|{Error Message if validation fails};...
validate_captcha: {Text Field They Enter String Into}|{Hidden Field With Encrypted String ("CFMX_COMPAT","HEX")}|{Error Message};...
validate_state:  {form field for state} | {comma delimted list of states for comparison (these are the valid states)}

Returns a query with the following columns:

Fields - The form fields that have errors.
Messages - The error messages associated with each field.

Arugments:

fields (required) - the form structure passed to the page the form posts to.
keystring (Optional) - used if using validate_captcah.  Pass in the key you used to encrypt the captcha string so it can be decryted and compared.

Example (sample.cfm):

<!---***START EXAMPLE***--->
<cfif NOT isdefined('form.firstname')>
<form action="sample.cfm" name="sampleform" method = "post" >
<h2>Demo Form</h2>
First name*: <input name="firstname" type = "text" value="" size="25">
<br>
Last Name*: <input name="lastname" type="text" value="" size="25">
<br>
<input type = "submit" value="Validate Form" name="submitbtn">
<input type = "hidden" value="firstname|Enter your firstname please;lastname|Enter a lastname please" name="validate_require">
</form>
</cfif>

<CFIF ISDEFINED('form.firstname')>
<cfinvoke component="functions.validation" method="validate" returnvariable="qValidation">
	<cfinvokeargument name="fields" value="#form#">
</cfinvoke>

<cfif qValidation.recordcount GT 0>
	There were some errors:<br>
	<cfoutput query = "qValidation">
		#messages#<br>
	</cfoutput>

<cfelse>
	There were no errors in your form!
</cfif>
</CFIF>
<!---***END EXAMPLE***--->
--->
<cfcomponent>
    <cffunction name="validate" access="public" returntype="query">
       <cfargument name="fields" type="struct" required="yes" hint="Structure of form fields submitted.">
       <cfargument name="keystring" type="string" required="no" default="botcheck" 
       hint="When using validation_captcha pass in the key to decrypt the string.">	

            <!---create blank query--->
            <cfset qErrors = QueryNew("")>
            <cfset error_forms = "">
            <cfset error_messages = "">
            
            <!---loop over all form fields passed--->
            <cfloop collection="#fields#" item="VarName">
				
				<!---If validation field is found then check if form field is present.  If not add to error list.--->
                <cfif VarName IS 'validate_require'>
                	<cfset FormName = 'form.#VarName#'>
                    <cfset VarVal = evaluate(FormName)>               
					                  
                    <cfloop list="#VarVal#" delimiters=";" index="thislist">
						<cfset fieldid = #listgetat(thislist, 1, "|")#>
                        <cfset fieldid = trim(fieldid)>
						<cfset fieldtocheck = 'form.#fieldid#'>
                        <cfset thismessage = #listgetat(thislist, 2, "|")#>
                        
                        <!---if not defined then error--->
                        <cfif isdefined(fieldtocheck)>
                            <cfset fieldval = evaluate(fieldtocheck)>
							<!---if empty then append to error list--->                            
                            <cfif len(trim(fieldval)) LT 1>
								<cfset error_forms = listappend(error_forms, fieldid, "|")>
                                <cfset error_messages = listappend(error_messages, thismessage, "|")>
                            </cfif> 
                        <cfelse>
                        	<!---a required field is missing--->
                        	<cfset error_forms = listappend(error_forms, fieldid, "|")>
                        	<cfset error_messages = listappend(error_messages, thismessage, "|")>
                         </cfif>
                    </cfloop>
                </cfif><!---end empty field validation--->               

 				<!---**email validation**--->
                 <cfif VarName IS 'validate_email'>
                	<cfset FormName = 'form.#VarName#'>
                    <cfset VarVal = evaluate(FormName)>               
					                  
                    <cfloop list="#VarVal#" delimiters=";" index="thislist">
						<cfset fieldid = #listgetat(thislist, 1, "|")#>
                        <cfset fieldid = trim(fieldid)>
						<cfset fieldtocheck = 'form.#fieldid#'>
                        <cfset thismessage = #listgetat(thislist, 2, "|")#>
                        
                        <!---if not defined then error--->
                        <cfif isdefined(fieldtocheck)>
                            <cfset fieldval = evaluate(fieldtocheck)>
							<!---if it doesn't contain the @ or . then it's invalid--->                            
                            <cfif NOT fieldval CONTAINS '@' or NOT fieldval CONTAINS '.'>
								<cfset error_forms = listappend(error_forms, fieldid, "|")>
                                <cfset error_messages = listappend(error_messages, thismessage, "|")>                                
							<cfelse>
                            	<!---if it's not formated correctly, it's invalid--->
	                            <cfif listlen(fieldval, "@") LT 2>
									<cfset error_forms = listappend(error_forms, fieldid, "|")>
                                    <cfset error_messages = listappend(error_messages, thismessage, "|")>
                                </cfif>
								<cfif listlen(fieldval, ".") LT 2>
									<cfset error_forms = listappend(error_forms, fieldid, "|")>
                                    <cfset error_messages = listappend(error_messages, thismessage, "|")>
                                </cfif>
							</cfif>                                	
                        <cfelse>
                        	<!---a required field is missing--->
                        	<cfset missingmessage = '#fieldid# is missing.'>
                        	<cfset error_forms = listappend(error_forms, fieldid, "|")>
                            <cfset error_messages = listappend(error_messages, missingmessage, "|")>
                        </cfif>
                    </cfloop>
                </cfif><!---end email validation--->

 				<!---**password validation**--->
                <!---{password field}|{confirmation password field}|{error message}--->
                 <cfif VarName IS 'validate_password'>
                	<cfset FormName = 'form.#VarName#'>
                    <cfset VarVal = evaluate(FormName)>               
					                  
                    <cfloop list="#VarVal#" delimiters=";" index="thislist">
						<cfset fieldid = #listgetat(thislist, 1, "|")#>
                        <cfset fieldid = trim(fieldid)>
						<cfset fieldtocheck = 'form.#fieldid#'>
						<cfset fieldid2 = #listgetat(thislist, 2, "|")#>
                        <cfset fieldid2 = trim(fieldid2)>
                        <cfset fieldtocheck2 = 'form.#fieldid2#'>
                        <cfset thismessage = #listgetat(thislist, 3, "|")#>
                        
                        <!---if not defined then error--->
                        <cfif NOT isdefined(fieldtocheck)>
                        </cfif>
                        
                        <cfif NOT isdefined(fieldtocheck2)>
                        </cfif>
                        
                        <cfif isdefined(fieldtocheck) AND isdefined(fieldtocheck2)>
                        	<cfset fieldval = evaluate(fieldtocheck)>
                            <cfset fieldval2 = evaluate(fieldtocheck2)>
                            
                            <!---they do not match so add error--->
                            <cfif NOT fieldval IS fieldval2>
								<cfset error_forms = listappend(error_forms, fieldid, "|")>
                                <cfset error_messages = listappend(error_messages, thismessage, "|")>
                            </cfif>
                        </cfif>
						
                    </cfloop>
                </cfif> 
				<!---end password validation--->
			
				<!---***catpcha validation***--->
                <!---{text entry form}|{encrypted value}|{error message}--->
                 <cfif VarName IS 'validate_captcha'>
                	<cfset FormName = 'form.#VarName#'>
                    <cfset VarVal = evaluate(FormName)>               
					                  
                    <cfloop list="#VarVal#" delimiters=";" index="thislist">
						<cfset fieldid = #listgetat(thislist, 1, "|")#>
                        <cfset fieldid = trim(fieldid)>
						<cfset fieldtocheck = 'form.#fieldid#'>
						<cfset fieldid2 = #listgetat(thislist, 2, "|")#>
                        <cfset fieldid2 = trim(fieldid2)>
                        <cfset fieldtocheck2 = 'form.#fieldid2#'>
                        <cfset thismessage = #listgetat(thislist, 3, "|")#>
                        
                        <!---if not defined then error--->
                        <cfif NOT isdefined(fieldtocheck)>
                        </cfif>
                        
                        <cfif NOT isdefined(fieldtocheck2)>
                        </cfif>
                        
                        <cfif isdefined(fieldtocheck) AND isdefined(fieldtocheck2)>
                        	<cfset fieldval = evaluate(fieldtocheck)>
                            <cfset fieldval2 = evaluate(fieldtocheck2)>
                            
							<!--- Decrypt the check value. --->
                            <cfset strCaptcha = Decrypt(fieldval2, keystring, "CFMX_COMPAT","HEX") />
            				<cfif NOT (strCaptcha EQ fieldval)>
								<cfset error_forms = listappend(error_forms, fieldid, "|")>
                                <cfset error_messages = listappend(error_messages, thismessage, "|")>
                            </cfif>                            	
						</cfif>            
      				</cfloop>
       	 		</cfif><!---end if using captcha--->

 				<!---**state validation**--->
                <!---{state field}|{comma delimted list of valid states}|{error message}--->
                 <cfif VarName IS 'validate_state'>
                	<cfset FormName = 'form.#VarName#'>
                    <cfset VarVal = evaluate(FormName)>               
					                  
                    <cfloop list="#VarVal#" delimiters=";" index="thislist">
						<cfset fieldid = #listgetat(thislist, 1, "|")#>
                        <cfset fieldid = trim(fieldid)>
						<cfset fieldtocheck = 'form.#fieldid#'>
						<cfset valid_states = #listgetat(thislist, 2, "|")#>
                        <cfset thismessage = #listgetat(thislist, 3, "|")#>
                        
                        <!---if not defined then error--->
                        <cfif NOT isdefined(fieldtocheck)>
                        </cfif>

                        <cfif isdefined(fieldtocheck)>
							<cfset state_entered = evaluate(fieldtocheck)>
                            <cfset state_entered = trim(state_entered)>
    
                            <!---loop over the valid states and check the field to see if it's the same--->                        
                            <cfset foundit = 'No'>
                            <cfloop list="#valid_states#" delimiters="," index="this_state">
                                <cfset this_state = trim(this_state)>
								<cfif this_state IS state_entered>
                                    <cfset foundit = 'Yes'>
                                </cfif>
                            </cfloop>
                            
                            <!---If it wasn't found in the list show the error--->
                            <cfif foundit IS 'No'>
								<cfset error_forms = listappend(error_forms, fieldid, "|")>
                                <cfset error_messages = listappend(error_messages, thismessage, "|")>
                            </cfif>
                        </cfif>
						
                    </cfloop>
                </cfif> 
				<!---end state validation--->

 				<!---**birthday validation**--->
                 <cfif VarName IS 'validate_birthday'>
                	<cfset FormName = 'form.#VarName#'>
                    <cfset VarVal = evaluate(FormName)>               
					                  
                    <cfloop list="#VarVal#" delimiters=";" index="thislist">
					<cfif listlen(thislist, "|") GT 3>
						<cfset field_bmonth = #listgetat(thislist, 1, "|")#>
						<cfset field_bday = #listgetat(thislist, 2, "|")#>
						<cfset field_byear = #listgetat(thislist, 3, "|")#>
                        <cfset thismessage = #listgetat(thislist, 4, "|")#>
                        
                        <!---if not defined then error--->
                        <cfif NOT isdefined(field_bmonth)>
                        </cfif>
                        <cfif NOT isdefined(field_bday)>
                        </cfif>
                        <cfif NOT isdefined(field_byear)>
                        </cfif>                                                

                        <cfif isdefined(field_bmonth) AND isdefined(field_bday) AND isdefined(field_byear)>
							<cfset date_m = evaluate(field_bmonth)>
                            <cfset date_d = evaluate(field_bday)>
                            <cfset date_y = evaluate(field_byear)>

                            <cfset date_string = "#date_m#/#date_d#/#date_y#">
								<cfif NOT isdate(date_string)>                         
									<cfset error_forms = listappend(error_forms, 'birthday', "|")>
	                                <cfset error_messages = listappend(error_messages, thismessage, "|")>
								</cfif>
                        </cfif>
					<cfelse>
						<cfset error_messages = 'Birthday field missing.'>
                        <cfset error_forms = listappend(error_forms, 'birthday', "|")>
                        <cfset error_messages = listappend(error_messages, thismessage, "|")>
                    </cfif>	
                    </cfloop>
                </cfif> 
				<!---end birth date validation--->

                           
            </cfloop><!---end loop over collection--->

		<!---build query--->
        <cfif listlen(error_forms, "|") GT 0>
			<cfset aErrors = listtoarray(error_forms, "|", true)>
            <cfset aMessages = listtoarray(error_messages, "|", true)>
            
            <cfset "nColumnNumber1" = QueryAddColumn(qErrors, "fields", aErrors)>
            <cfset "nColumnNumber2" = QueryAddColumn(qErrors, "messages", aMessages)>
        </cfif>
       <cfreturn qErrors>
       </cffunction>
</cfcomponent>